// (function () {
// 页面全局配置
var config = {
    name: '', // 歌曲名字
    meter: '4/4', // 节拍 表示4分音符为一拍，每小节4拍
    speed: 1, // 音乐速度
    isPlay: false, // 开启弹奏模式
    score: [], // 存放谱子
    beat: 67,
    editNote : -1,//当前编辑的音符
    editEnt:null,//当前编辑显示
}
config.sTime = 15000 / config.beat //播放速度
// 获取默认时值 
config.duration = +config.meter.split('/')[1];
// 默认模板
config.meterDefaultHtml = `<div class="meter edit"><div class="col edit" data-duration="${config.duration}"></div></div>`;
config.colDefaultHtml = `<div class="col edit" data-duration="${config.duration}"></div>`;
config.restDefaultHtml = `<div class="note note-rest"><p class="note-main">0</p></div>`;
config.emptyNoteHtml = `<div class="note-empty">—</div>`;
//时值表达与数值关系（音符与时值的）
let q = {
    semibreve: 16,
    2: 8,
    8: 2,
    16: 1,
    32: 0.5,
    4: 4
};
//当前音符是否完整
isComplete = () => {
    try {
        return config.editNote==-1||config.score[config.editNote][1]||config.score[config.editNote][1]==0
    } catch (e) {
        return false
    }
}
//键盘与按键关系
var key = {
    q: 1,
    w: 2,
    e: 3,
    r: 4,
    t: 5,
    a: 6,
    s: 7,
    d: 11,
    f: 12,
    g: 13,
    z: 14,
    x: 15,
    c: 16,
    v: 17,
    b: 21,
    Enter: 'key-add',
    u: 'key-whole',
    i: 'key-2',
    o: 'key-4',
    j: 'key-8',
    k: 'key-16',
    l: 'key-32',
    ' ': 'key-add',
    ArrowLeft: 'key-pre',
    ArrowRight: 'key-next',
    Backspace: 'key-del'
}
//页面按钮与事件绑定
var btn = {
    'key-whole': semibreve,
    'key-2': halfNote,
    'key-4': quarterNote,
    'key-8': quaverNote,
    'key-16': semiquaverNote,
    'key-32': demisemiquaverNote,
    'key-dot': dottedNote,
    'key-triplet': triplet,
    'key-0': ()=>{notation(0)},//restNote,
    'key-add': ()=>{config.score.length==0?doAdd():isComplete()&&doAdd()},
    'key-del': doDelete,
    'key-pre': ()=>{isComplete()?doPre():doDelete()},
    'key-next':()=>{isComplete()?doNext():doDelete()},
    'key-finish': ()=>{isComplete()?doFinish():doDelete()},
    'key-play': ()=>{isComplete()?doPlay():doDelete()},
    other: k=>{makeSound(1.5, k);notation(+k)}
}

/* 键盘与页面按钮绑定 */
$('body').on('keyup', k => {
    key[k.key] && (btn[key[k.key]] ? btn[key[k.key]]() : btn.other(key[k.key]));
})
/* 点击页面按钮 */
$('body').on('click', '.key', function () {
    let key = $(this).attr('data-key');
    $(this).addClass('key-scale-animation');
    setTimeout(() => {
        $(this).removeClass('key-scale-animation');
    }, 500);
    btn[key] ? btn[key]() : btn.other(key);
});
/* 点击简谱编辑 */
$('body').on('click', '.col', function () {
    doEdit($(this));
    config.editNote=getIndexOfEdit();

})
/* 取消编辑 */
$('.main').on('click', function (event) {
    changeScore(config.editNote, 1);
    config.editEnt.remove()
        config.editEnt=null
        config.editNote=-1
})
doResize();
$(window).resize(function () {
    doResize();
    let windowWidth = $(window).width();
    if (windowWidth < 376) {
        alert('建议横屏体验');
    }
});
// 切换横竖屏处理的部分样式
function doResize() {
    if (/(iPhone|iPad|iPod|iOS|Android)/i.test(navigator.userAgent)) {
        $('.footer .keys').css({
            'width': '100%',
            'min-width': 'auto'
        });
        $('.footer .keys .key-group').css('margin-bottom', '5px');
        let keyHeight = $('.footer .keys .key-group .key').outerWidth();
        let shrink = (keyHeight / 60).toFixed(1);
        $('.footer .keys .key-group .key').css('height', keyHeight + 'px')
        $('.footer .keys .key-group .key .key-desc').css('transform', 'scale(' + shrink + ')');
        $('.footer .keys .key-group .key .key-title').css('transform', 'scale(' + shrink + ')');
    }
}
/** 添加编辑框 */
function doEdit($col) {
    config.editEnt&&config.editEnt.removeClass('edit');
    if($col.length!=0){config.editEnt=$col.addClass('edit');
    document.querySelector('.edit').scrollIntoView();}else {config.editEnt=null;config.editNote=-1}
}
/** 增加按钮处理 */
function doAdd() {
    if (!config.editEnt||config.editEnt.length==0) {
        // 没有编辑框，直接在末尾追加
        changeScore(config.score.length, 0, [config.duration]);
        $('.notes').append(config.colDefaultHtml);
        config.editNote=config.score.length-1
    } else {
        // 在编辑框的后面追加
        changeScore(++config.editNote, 0, [config.duration])
        config.editEnt.removeClass('edit');
        switch (config.duration) {
            case 24:
                config.editEnt.next('.note-empty').next('.note-empty').next('.note-empty').next('.note-empty').next('.note-empty').after(config.colDefaultHtml)
                break;
            case 16:
                config.editEnt.next('.note-empty').next('.note-empty').next('.note-empty').after(config.colDefaultHtml)
                break;
            case 12:
                config.editEnt.next('.note-empty').next('.note-empty').after(config.colDefaultHtml)
                break;
            case 8:
                config.editEnt.next('.note-empty').after(config.colDefaultHtml)
                break;
            default:
                config.editEnt.after(config.colDefaultHtml)
                break;
        }
    }
    config.editEnt = $('.col.edit')
    document.querySelector('.edit').scrollIntoView();
}
/** 删除按钮处理 */
function doDelete() {
    if (config.editEnt.length!=0) {
        changeScore(config.editNote, 1);
        config.editEnt.remove()
        doEdit($('.col').eq(config.editNote==0?config.editNote:--config.editNote))
        // config.editNote==0?doEdit(config.editEnt.next()):(doEdit(config.editEnt.remove().prev()),++config.editNote)
    }
}
/** 上一个 按钮处理 */
function doPre() {
    config.editEnt&&config.editNote> 0&&(doEdit(config.editEnt.prev()),--config.editNote)
}
/** 下一个 按钮处理 */
function doNext() {
    config.editEnt&&config.editNote< config.score.length-1&&(doEdit(config.editEnt.next()),++config.editNote)
}
/** 查看/显示简谱 */
function doFinish() {
    let e = `return{b=${config.speed}\n
        ,--上边这个数字是速度，按需修改\n
        sTime=15000/${config.beat}\n
        ,--上边这个除号后的数字表示每分钟的拍数，按需修改\n
        score={--下边开始是谱子主体，可单独复制出来加到其它谱子\n`;
    for (u in config.score) {
        var n = config.score[u];
        e += "{"
        for (i in n) {
            let n2 = n[i] == 0 ? 8 : n[i];
            e += i == '0' ? n2 : "," + n2;
        }
        e += "},"
    }
    e = e.substr(0, e.length - 1) + '\n\n--谱子结束\n}}'
    $(".note-textarea").toggle().val(e).css('top', '80px')
}
/** 简谱按钮事件处理 */ // TODO
function notation(key) {
    let index = config.editNote//getIndexOfEdit();
    // 处于编辑状态才重新渲染页面
    if (index !== -1) {
        let noteNow=config.score[index]
        let duration = noteNow[0];
        let have=false;
        for (let i = 1; i < noteNow.length; ++i) {
            if (noteNow[i] === key) {
                noteNow.splice(i, 1)
                have = true
                break;
            }
        }
        have || (noteNow[noteNow.length] = key)
        // 排序并更新score
        noteNow=noteNow.slice(1)
        noteNow.sort(function (a, b) {
            return a - b;
        }).unshift(duration);
        changeScore(index, 1, noteNow);
        clearNotes(duration);
        switch (true) {
            case duration === 24:
                randerCol(config.editEnt, config.score[index]);
                randerEmptyNote(config.editEnt, 5);
                break;
            case duration === 16:
                randerCol(config.editEnt, config.score[index]);
                randerEmptyNote(config.editEnt, 3);
                break;
            case duration === 12:
                randerCol(config.editEnt, config.score[index]);
                randerEmptyNote(config.editEnt, 2);
                break;
            case duration === 8:
                randerCol(config.editEnt, config.score[index]);
                randerEmptyNote(config.editEnt, 1);
                break;
            case duration === 2 || duration === 1.32:
                randerQuaverNote(config.editEnt, config.score[index]);
                break;
            case duration === 1 || duration === 0.66:
                randerSemiquaverNote(config.editEnt, config.score[index]);
                break;
            case duration === 0.5 || duration === 0.33:
                randerDemisemiquaverNote(config.editEnt, config.score[index]);
                break;
            default:
                randerCol(config.editEnt, config.score[index]);
                break;
        }
    }
}
/** 全音符按钮事件 */
function semibreve() {
    if (config.editEnt.length!=0) {
        let duration = getDuration();
        if(duration == 24 || duration == 16){config.duration=duration;return}
        let index = config.editNote//getIndexOfEdit(); // 在大数组的下标
        let n = 3;
        clearNotes(duration);
        // 与连音符互斥
        if (config.editEnt.hasClass('liaison-left') || config.editEnt.hasClass('triplet') || config.editEnt.hasClass('liaison-right')) {
            clearTriplet(config.editEnt, index);
        }
        if (config.editEnt.hasClass('note-dot') || duration === 12) {
            config.editEnt.removeClass('note-dot');
            duration = 24;
            n = 5;
        } else {
            duration = 16;
        }
        config.score[index][0]=duration;
        randerCol(config.editEnt, config.score[index]);
        randerEmptyNote(config.editEnt, n);
    }
}
/** 二分音符按钮事件 */
function halfNote() {
    if (config.editEnt.length!=0){
        let duration = getDuration();
        if (duration == 12 || duration == 8){config.duration=duration;return}
        let index = config.editNote//getIndexOfEdit();
        let n = 1;
        clearNotes(duration);
        // 与连音符互斥
        if (config.editEnt.hasClass('liaison-left') || config.editEnt.hasClass('triplet') || config.editEnt.hasClass('liaison-right')) {
            clearTriplet(config.editEnt, index);
        }
        if (config.editEnt.hasClass('note-dot') || duration === 24) {
            config.editEnt.removeClass('note-dot');
            duration = 12;
            n = 2;
        } else {
            duration = 8;
        }
        config.score[index][0]=duration; // 更新时值
        randerCol(config.editEnt, config.score[index]);
        randerEmptyNote(config.editEnt, n);
    }
}
/** 四分音符 */
function quarterNote() {
    if (config.editEnt.length!=0){
        let duration = getDuration();
        if( duration == 4||duration == 6) {config.duration=duration;return}
        let index = config.editNote//getIndexOfEdit();
        // 与连音符互斥
        clearNotes(duration);
        if (config.editEnt.hasClass('liaison-left') || config.editEnt.hasClass('triplet') || config.editEnt.hasClass('liaison-right')) {
            clearTriplet(config.editEnt, index);
        }
        if (config.editEnt.hasClass('note-dot') || duration === 24 || duration === 12) {
            duration = 6;
        } else {
            duration = 4;
        }
        config.score[index][0]=duration;
        randerCol(config.editEnt, config.score[index]);
    }
}
/** 八分音符 */
function quaverNote() {
    if (config.editEnt.length!=0){
        let duration = getDuration();
        if( duration == 2 ||duration==3) {config.duration=duration;return}
        let index = config.editNote//getIndexOfEdit();
        clearNotes(duration);
        if (config.editEnt.hasClass('liaison-left') || config.editEnt.hasClass('triplet') || config.editEnt.hasClass('liaison-right')) {
            clearTriplet(config.editEnt, index);
        }
        if (config.editEnt.hasClass('note-dot') || duration === 24 || duration === 12) {
            duration = 3
        } else {
            duration = 2;
        }
        config.score[index][0]=duration;
        randerQuaverNote(config.editEnt, config.score[index]);
    }
}
/** 十六分分音符 */
function semiquaverNote() {
    if (config.editEnt.length!=0){
        let duration = getDuration();
        if(duration == 1 ||duration == 1.5) {config.duration=duration;return}
        let index = config.editNote//getIndexOfEdit();
        clearNotes(duration);
        if (config.editEnt.hasClass('liaison-left') || config.editEnt.hasClass('triplet') || config.editEnt.hasClass('liaison-right')) {
            clearTriplet(config.editEnt, index);
        }
        if (config.editEnt.hasClass('note-dot') || duration === 24 || duration === 12) {
            duration = 1.5;
        } else {
            duration = 1;
        }
        config.score[index][0]=duration;
        randerSemiquaverNote(config.editEnt, config.score[index]);
    }
}
/** 三十二分音符 */
function demisemiquaverNote() {
    if (config.editEnt.length!=0){
        let duration = getDuration();
        if( duration == 0.5 || duration == 0.75) {config.duration=duration;return}
        let index = getIndexOfEdit();
        clearNotes(duration);
        if (config.editEnt.hasClass('liaison-left') || config.editEnt.hasClass('triplet') || config.editEnt.hasClass('liaison-right')) {
            clearTriplet(config.editEnt, index);
        }
        if (config.editEnt.hasClass('note-dot') || duration === 24 || duration === 12) {
            duration = 0.75;
        } else {
            duration = 0.5;
        }
        config.score[index][0]=duration;
        randerDemisemiquaverNote(config.editEnt, config.score[index]);
    }
}
/** 三连音音符 */
function triplet() {
    let $c1 = config.editEnt;
    let $c2 = $c1.next();
    let $c3 = $c2.next();
    let duration1 = getDuration($c1);
    let duration2 = getDuration($c2);
    let duration3 = getDuration($c3);
    let index = config.editNote//getIndexOfEdit();
    // 添加三连 和 取消三连
    if ($c1.length > 0 && !checkTriplet(duration1, duration2, duration3)) return;
    if (checkTriplet(duration1, duration2, duration3) === 1) {
        config.score[index].splice(0, 1, duration1 * 0.66);
        config.score[index + 1].splice(0, 1, duration2 * 0.66);
        config.score[index + 2].splice(0, 1, duration3 * 0.66);
        randerTriplet($c1, $c2, $c3);
    } else if (checkTriplet(duration1, duration2, duration3) === 2) {
        config.score[index].splice(0, 1, duration1 / 0.66);
        config.score[index + 1].splice(0, 1, duration2 / 0.66);
        config.score[index + 2].splice(0, 1, duration3 / 0.66);
        cancleTriplet($c1, $c2, $c3);
    }
}
/** 休止符按钮事件 */
function restNote() {
    if (config.editEnt.length!=0) {
        let index = config.editNote//getIndexOfEdit();
        //clearNotes(getDuration());
        // if (config.editEnt.hasClass('liaison-left') || config.editEnt.hasClass('triplet') || config.editEnt.hasClass('liaison-right')) {
        //     clearTriplet(config.editEnt, index);
        // }
        changeScore(index, 1, [config.duration, 0]);
        config.editEnt.html(config.restDefaultHtml);
        config.editEnt.attr('data-duration', 4);
    }
}
/** 附点音符 */
function dottedNote() {
    let duration = getDuration(); // 获取当前时值
    // 全音符与二分音符不能添加浮点音符
    if (config.editEnt.length!=0) {
        let index = config.editNote//getIndexOfEdit();
        // 与连音符互斥
        if (config.editEnt.hasClass('liaison-left') || config.editEnt.hasClass('triplet') || config.editEnt.hasClass('liaison-right')) {
            clearTriplet(config.editEnt, index);
            duration = getDuration(); // 若清除三连，需要重新获取一下当前的时值
        }
        switch (duration) {
            case 24:
                removeEmptyNote(config.editEnt, 2);
                duration = 16;
                break;
            case 16:
                randerEmptyNote(config.editEnt, 2);
                duration =24;
                break;
            case 12:
                removeEmptyNote(config.editEnt, 1);
                duration =8;
                break;
            case 8:
                randerEmptyNote(config.editEnt, 1);
                duration = 12;
                break;
            default:
                config.editEnt.hasClass('note-dot') ? (duration /= 1.5) : (duration *= 1.5);
                config.editEnt.toggleClass('note-dot');
                break;
        }
        config.score[index][0]=duration;
        config.editEnt.attr('data-duration', duration);
    }
}
/**
 * 渲染编辑列的简谱
 * @param {Array} notes 简谱数组
 */
function randerCol($col, notes) {
    // console.log(notes)
    $col.html('');
    $col.attr('data-duration', notes[0])
    let template1 = '', // 低音
        template2 = '', // 中音
        template3 = ''; // 高音
    for (let i = 1; i < notes.length; i++) {
        // if (notes[i] === 0) {
        //     template2 = `<div class="note note-rest"><p class="note-main">0</p></div>`;
        // } else {
            let decade = notes[i] - notes[i] % 10; // 判断高中低音 decade：0-低，1-中，2-高
            if (decade == 0) {
                template1 += `<div class="note"><p class="note-main">${notes[i] % 10}</p><p class="pitch-low">·</p></div>`;
            } else if (decade == 10) {
                template2 += `<div class="note"><p class="note-main">${notes[i] % 10}</p></div>`;
            } else if (decade == 20) {
                template3 += `<div class="note pitch-high"><p class="note-main">${notes[i] % 10}</p></div>`;
            }

        // }
    }
    $col.append(template3 + template2 + template1);
}
/** 添加渲染指定数量的横杠 */
function randerEmptyNote($col, n) {
    let html = '';
    for (let i = 0; i < n; i++) {
        html += config.emptyNoteHtml;
    }
    $col.after(html);
}
/** 删除指定数量横杠 */
function removeEmptyNote($col, n) {
    while (n--) {
        $col.next('.note-empty').remove();
    }
}
/** 渲染八分音符 */
function randerQuaverNote($col, notes) {
    randerCol($col, notes);
    $('.col.edit .note .note-main').after(`<p class="beat-8"></p>`);
}
/** 渲染十六分音符 */
function randerSemiquaverNote($col, notes) {
    randerCol($col, notes);
    $('.col.edit .note .note-main').after(`<p class="beat-8"></p><p class="beat-16"></p>`);
}
/** 渲染三十二分音符 */
function randerDemisemiquaverNote($col, notes) {
    randerCol($col, notes);
    $('.col.edit .note .note-main').after(`<p class="beat-8"></p><p class="beat-16"></p><p class="beat-32"></p>`);
}
/** 渲染三连音 */
function randerTriplet($c1, $c2, $c3) {
    let index = getIndexOfEdit($c1);
    $c1.attr('data-duration', config.score[index][0]);
    $c2.attr('data-duration', config.score[index + 1][0]);
    $c3.attr('data-duration', config.score[index + 2][0]);
    $c1.addClass('liaison-left');
    $c2.addClass('triplet');
    $c3.addClass('liaison-right');
}
/** 取消渲染三连音 */
function cancleTriplet($c1, $c2, $c3) {
    let index = getIndexOfEdit($c1);
    $c1.attr('data-duration', config.score[index][0]);
    $c2.attr('data-duration', config.score[index + 1][0]);
    $c3.attr('data-duration', config.score[index + 2][0]);
    $c1.removeClass('liaison-left');
    $c2.removeClass('triplet');
    $c3.removeClass('liaison-right');
}
/** 清除该列原有音符样式（仅清除全音符、二分、八分、十六分、三十二分） */
function clearNotes(duration) {
    let $edit = $('.edit');
    if (duration === 24 || duration === 16 || duration === 12 || duration === 8) {
        while ($edit.next().hasClass('note-empty')) {
            $edit.next().remove();
        }
    } else if (duration !== 2 || duration !== 1.32) {
        $('.col.edit .beat-8').remove();
    } else if (duration !== 1 || duration !== 0.66) {
        $('.col.edit .beat-8').remove();
        $('.col.edit .beat-16').remove();
    } else if (duration !== 0.5 || duration !== 0.33) {
        $('.col.edit .beat-8').remove();
        $('.col.edit .beat-16').remove();
        $('.col.edit .beat-32').remove();
    }
}
/** 清除三连音（更新config.score也清除页面效果） */
function clearTriplet($col, index) {
    let index1, index2, index3, duration1, duration2, duration3;
    if ($col.hasClass('liaison-left')) {
        index1 = index, index2 = index + 1, index3 = index + 2;
    } else if ($col.hasClass('triplet')) {
        index1 = index - 1, index2 = index, index3 = index + 1;
    } else if ($col.hasClass('liaison-right')) {
        index1 = index - 2, index2 = index - 1, index3 = index;
    }
    duration1 = config.score[index1][0] / 0.66;
    duration2 = config.score[index2][0] / 0.66;
    duration3 = config.score[index3][0] / 0.66;
    config.score[index1][0]=duration1;
    config.score[index2][0]=duration2;
    config.score[index3][0]=duration3;
    let col = $('.col');
    col.eq(index1).attr('data-duration', duration1).removeClass('liaison-left');
    col.eq(index2).attr('data-duration', duration2).removeClass('triplet');
    col.eq(index3).attr('data-duration', duration3).removeClass('liaison-right');
}
/** 获取当前编辑在简谱数组中的下标 获取不到返回-1 */
function getIndexOfEdit() {
    let $cols = $('.col');
    for (let i = 0; i < $cols.length; i++) {
        if ($cols[i].classList.contains('edit')) {
            return i;
        }
    }
    return -1;
}
/** 获取当前编辑在meter中的下标和所有col的长度 */
function getSubIndex($col) {
    let $cols = $col.parent().children('.col');
    for (let i = 0; i < $cols.length; i++) {
        if ($cols[i].classList.contains('edit')) {
            return {
                index: i,
                len: $cols.length
            };
        }
    }
}
/**
 * 判断连续的三个时值是否具备追加三连音条件
 * @return {Number} 0/undefined-表示不具备添加条件，1-表示可添加，2-表示已添加
 */
function checkTriplet(duration1, duration2, duration3) {
    if (!duration1 || !duration2 || !duration3) return;
    if (duration1 ===  duration2  && duration2===duration3 )
        if(duration1=== 2 || duration1 === 1 || duration1 === 0.5 ) {
            return 1;
        } else if (duration1 === 1.32 || duration1 === 0.66 || duration1 === 0.33 ) {
            return 2;
        }
    return 0;

}
/**
 * 根据下标更新简谱数组
 * 用法：
 *      删除 - changeScore(起始下标，删除的项数)
 *      插入 - changeScore(起始下标, 0 ,要插入的项)
 *      修改 - changeScore(起始下标, n ,要插入的项)
 * @param {Number} index  指定开始修改的下标
 * @param {Number} n      0-表示插入    大于0表示从index开始要修改的项数
 * @param {Array} item    指定要修改的项，不指定则表示前两参数的作用是删除
 */
function changeScore(index, n, ...item) {
    item ? (config.score.splice(index, n, ...item)) : (config.score.splice(index, n));
}
/** 获取当前编辑的简谱时值 */
function getDuration($col) {
    return $col?parseFloat($col.attr('data-duration')):config.score[config.editNote][0];

}

function deepCopy(obj1) {
    var obj2 = Array.isArray(obj1) ? [] : {};
    if (obj1 && typeof obj1 === "object") {
        for (var i in obj1) {
            if (obj1.hasOwnProperty(i)) {
                // 如果子属性为引用数据类型，递归复制
                if (obj1[i] && typeof obj1[i] === "object") {
                    obj2[i] = deepCopy(obj1[i]);
                } else {
                    // 如果是基本数据类型，只是简单的复制
                    obj2[i] = obj1[i];
                }
            }
        }
    }
    return obj2;
}

//创建一个音频上下文
var ctx;
// var sounds = [130, 147, 165, 175, 196, 220, 246, 262, 294, 330, 349, 392, 440, 494, 523, 587, 659, 698, 784, 880, 988, 1047];
var sounds = [0, 262, 294, 330, 349, 392, 440, 494, 0, 0, 0, 523, 587, 659, 698, 784, 880, 988, 0, 0, 0, 1047];
// 得到一个音频上下文
function setContext() {
    var AudioContext = window.AudioContext || window.webkitAudioContext;
    if (!ctx) {
        //保证，多次调用该函数，只创建一个上下文
        ctx = new AudioContext();
    }
}

/**
 *
 * @param duration 时值
 * @param index 音符
 */
function makeSound(duration, index) {
    setContext(); //设置上下文
    var osc = ctx.createOscillator(); //得到音频振荡器
    var g = ctx.createGain(); //得到音量控制对象

    osc.connect(g); //连接 振荡器 和 音量控制对象
    osc.type = "sine"; //设置波形
    osc.frequency.value = sounds[index]; //设置频率

    g.connect(ctx.destination); //连接到系统默认设备
    g.gain.value = 0; //控制音量


    osc.start(); //不传递时间，则立即播放
    //音量在0.01秒内，从0变到0.6
    g.gain.linearRampToValueAtTime(0.6, ctx.currentTime + 0.01);
    //1.5秒后停止
    osc.stop(ctx.currentTime + duration);
    //音量在1.5秒内，从0.6变到0.01
    g.gain.exponentialRampToValueAtTime(0.01, ctx.currentTime + duration);
}

var player, status;
//暂停
function pause() {
    player && (clearInterval(player),player = null);
}
// 清除播放数据
function clearPlay() {
    pause();

    status = '';
}

function doPlay() {
    let time = 0 //运行时间
    let $note = $('.col');
    let s2 = deepCopy(config.score);
    let duration = 0;

    if (s2.length === 0) return;
    if (status === 'playing') {
        status = 'pause';
        pause();
        return;
    } else {
        status = 'playing';
        config.editNote = config.editNote === -1 || config.editNote + 1 === config.score.length ? 0 : config.editNote;
    }

    player = setInterval(function () {
        time += 10;
        if (time > duration) {
            if (config.editNote >= s2.length) {
                // 播放结束 大型清理现场
                config.editEnt.removeClass('edit');
                config.editEnt=null
                config.editNote=-1
                clearPlay();
                return;
            }
            duration = s2[config.editNote][0] * config.sTime;
            config.editEnt.removeClass('edit');
            config.editEnt=$note.eq(config.editNote).addClass('edit');
            for (let j = 1; j < s2[config.editNote].length; j++) {
                makeSound(duration / 1000, s2[config.editNote][j])
            }
            time = 0;
            ++config.editNote;
        }
    }, 10)
}